#include <linux/delay.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/ide.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define LEDDEVBASE_MAJOR  200
#define LEDDEVBASE_NAME   "leddev"

//寄存器物理地址
#define  CCM_CCGR1_BASE          (0X020C406C)
#define  SW_MUX_GPIO1_IO03_BASE  (0X020E0068)
#define  SW_PAD_GPIO1_IO03_BASE  (0X020E02F4)
#define  GPIO1_DR_BASE           (0X0209C000)
#define  GPIO1_GDIR_BASE         (0X0209C004)

//寄存器虚拟地址
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;




//开关模式
#define LEDON   1
#define LEDOFF  0

//开关led函数
void led_switch(unsigned char key)
{
    if (key == 1)
    {
        unsigned int val = readl(GPIO1_DR);
        val &= ~(1 << 3);
        writel(val, GPIO1_DR);
    }
    else 
    {
        unsigned int val = readl(GPIO1_DR);
        val  |= (1 << 3);
        writel(val, GPIO1_DR);
    }
        printk("%d\r\n", key);

}

static ssize_t leddevbase_open(struct inode * inode, struct file *fp)
{
    return 0;
}

static ssize_t leddevbase_read(struct file * fp, char __user *buf, size_t count, loff_t *off_t)
{
    return 0;
}

static ssize_t leddevbase_write(struct file * fp, const char __user *buf, size_t cnt, loff_t * offt)
{
    unsigned char databuffer[10];
    unsigned ledkey = 0;
    int retvalue = copy_from_user(databuffer, buf, cnt);
    if (retvalue < 0)
    {
        printk("kernel write failed \r\n");
        return -EFAULT;
    }
    ledkey = databuffer[0];

    //根据其值设置开关
    led_switch(ledkey);
    return 0;
}

static ssize_t leddevbase_close(struct inode *inode, struct file * fp)
{
    return 0;
}

static const struct file_operations leddevbase_op = {
    .owner = THIS_MODULE,
    .open  = leddevbase_open,
    .read  = leddevbase_read,
    .write = leddevbase_write,
    .release = leddevbase_close
};

//加载模块
static int __init leddevbase_init(void)
{
   
    //设置寄存器虚拟地址
    IMX6U_CCM_CCGR1   = ioremap(CCM_CCGR1_BASE, 4);
    SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);
    SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, 4);
    GPIO1_DR          = ioremap(GPIO1_DR_BASE, 4);
    GPIO1_GDIR        = ioremap(GPIO1_GDIR_BASE, 4);

    unsigned int val = readl(IMX6U_CCM_CCGR1);
    //清除原来led保存值，设置时钟
    val &= ~(3 << 26);
    val |= (3 << 26);
    writel(val, IMX6U_CCM_CCGR1);

    //设置GPIO1_IO03复用功能
    writel(5, SW_MUX_GPIO1_IO03);

    //设置GPIO1_IO03属性
    writel(0x10b0, SW_PAD_GPIO1_IO03);

    // 设置GPIO1_IO03为输出模式
    val  = readl(GPIO1_GDIR);
    val  &= ~(1 << 3); //清除以前设置
    val  |= (1 << 3); // 设置为输出模式
    writel(val, GPIO1_GDIR);

    //默认关闭led
    led_switch(LEDOFF);

    //注册设备驱动
    int retvalue = register_chrdev(LEDDEVBASE_MAJOR, LEDDEVBASE_NAME, &leddevbase_op);
    //判断
    if (retvalue <  0)
        printk("init led failed\r\n");
    else
        printk("init led sucess\r\n");
    return retvalue;

}

//卸载模块
static void __exit leddevbase_exit(void)
{
    //取消映射
    iounmap(IMX6U_CCM_CCGR1);
    iounmap(SW_PAD_GPIO1_IO03);
    iounmap(SW_MUX_GPIO1_IO03);
    iounmap(GPIO1_DR);
    iounmap(GPIO1_GDIR);

    unregister_chrdev(LEDDEVBASE_MAJOR, LEDDEVBASE_NAME);
    printk("exit led sucess\r\n");
    return;
}

module_init(leddevbase_init);
module_exit(leddevbase_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("shiyue");


